package MultiSnake;

import java.awt.*;
import java.awt.List;
import java.awt.event.*;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.*;
import javax.swing.*;

public class MultiSnake implements KeyListener, ClientInterface, java.io.Serializable {
	JFrame mainFrame;
	Canvas paintCanvas;
	JLabel myScoreLabel;
	JLabel oppScoreLabel;
	JLabel mySpeedLabel;
	MultiSnakeModel snakeModel = null;

	/*
	 * board size and snake size in client
	 */
	int Width;
	int Height;
	int nodeWidth;
	int nodeHeight;

	/*
	 * Set the initial position of snake
	 */
	int snakeX, snakeY;
	int clientIndex;
	String ip = "";
	
	ServerInterface server;
	
	public MultiSnake(int snakeX, int snakeY,
			String ip, boolean loggedIn) {
		this.ip = ip;
		snakeModel=new MultiSnakeModel(server, this, snakeX, snakeY);
		try {
			if (!loggedIn)
				throw new Exception("Not logged in.");
		} catch (Exception e) {
			new Client();
			return;
		}
		paintCanvas = new Canvas();
		try {
			this.snakeX = snakeX;
			this.snakeY = snakeY;
			mainFrame = new JFrame("Snake Game");
			Container cp = mainFrame.getContentPane();

			myScoreLabel = new JLabel("My Score:");
			mySpeedLabel = new JLabel("My Speed:");
			JLabel notice = new JLabel("press the space");
			Panel p = new Panel();
			p.setLayout(new GridLayout(1, 2));
			p.add(myScoreLabel);
			p.add(mySpeedLabel);
			p.add(notice);
			cp.add(p, BorderLayout.NORTH);

			oppScoreLabel = new JLabel("Opp score:");
			cp.add(oppScoreLabel, BorderLayout.SOUTH);

			Width = Server.Width;
			Height = Server.Height;
			nodeWidth = Server.nodeWidth;
			nodeHeight = Server.nodeHeight;

			paintCanvas.setSize(Width + 1, Height + 1);
			paintCanvas.addKeyListener(this);
			cp.add(paintCanvas, BorderLayout.CENTER);

			mainFrame.addKeyListener(this);
			mainFrame.pack();
			mainFrame.setResizable(false);
			mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			int width = Toolkit.getDefaultToolkit().getScreenSize().width;
			int height = Toolkit.getDefaultToolkit().getScreenSize().height;
			mainFrame.setLocation(width / 2 - Width / 2, height / 2 - Height
					/ 2);
			mainFrame.setVisible(true);
			// begin();
			/* Get the Registry! */
			Registry reg;
			try {
				reg = LocateRegistry.getRegistry(12345);

				/* Get the Server! */
				server = (ServerInterface) reg.lookup("Server");

				/* Register this client as Callback */
				server.register(this);
			} catch (RemoteException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (NotBoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} catch (Exception e) {
			JOptionPane
					.showMessageDialog(
							null,
							"can't connect to the server.Please make sure the server has been run!",
							"Error", JOptionPane.INFORMATION_MESSAGE);
			e.printStackTrace();
			new Client();
		}
	}

	public void keyPressed(KeyEvent e) {
		int keyCode = e.getKeyCode();
		if (keyCode == KeyEvent.VK_SPACE) {
			//begin(this.server);
			System.out.println("player press space="+this.clientIndex);
			try {
				this.server.startThreads();
			} catch (RemoteException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		
		if (snakeModel.myRunning)
			switch (keyCode) {
			case KeyEvent.VK_UP:
				snakeModel.changeDirection(MultiSnakeModel.UP);
				break;
			case KeyEvent.VK_DOWN:
				snakeModel.changeDirection(MultiSnakeModel.DOWN);
				break;
			case KeyEvent.VK_LEFT:
				snakeModel.changeDirection(MultiSnakeModel.LEFT);
				break;
			case KeyEvent.VK_RIGHT:
				snakeModel.changeDirection(MultiSnakeModel.RIGHT);
				break;
			case KeyEvent.VK_PAGE_UP:
				snakeModel.speedUp();
				break;
			case KeyEvent.VK_PAGE_DOWN:
				snakeModel.speedDown();
				break;
			default:
			}
	}

	public void keyReleased(KeyEvent e) {
	}

	public void keyTyped(KeyEvent e) {
	}

	public void repaint() {
		Graphics g = paintCanvas.getGraphics();

		/*
		 * Set the color of board
		 */
		g.setColor(Color.LIGHT_GRAY);
		g.fillRect(0, 0, Width, Height);

		/*
		 * Draw the snake
		 */
		g.setColor(Color.blue);
		LinkedList oppll = snakeModel.oppNodeArray;
		Iterator oppIt = oppll.iterator();
		while (oppIt.hasNext()) {
			Node n = (Node) oppIt.next();
			drawNode(g, n);
		}

		g.setColor(Color.BLACK);
		LinkedList myll = snakeModel.myNodeArray;
		Iterator myIt = myll.iterator();
		while (myIt.hasNext()) {
			Node n = (Node) myIt.next();
			drawNode(g, n);
		}

		/*
		 * food position
		 */
		if (snakeModel.food != null) {
			g.setColor(Color.RED);
			Node n = snakeModel.food;
			drawNode(g, n);
		}

		updateScore();
		updateSpeed();
	}

	public void drawNode(Graphics g, Node n) {
		Graphics2D g2 = (Graphics2D) g;
		RenderingHints rh = g2.getRenderingHints();
		rh.put(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setRenderingHints(rh);
		g2.fillOval(n.x * nodeWidth, n.y * nodeHeight, nodeWidth, nodeHeight);
	}

	public void updateScore() {
		String my = "My Score: " + snakeModel.myScore;
		myScoreLabel.setText(my);
		String you = "Oppo Score: " + snakeModel.oppScore;
		oppScoreLabel.setText(you);
	}

	public void updateSpeed() {
		String speed = "My Speed:" + snakeModel.mySpeed;
		mySpeedLabel.setText(speed);
	}

	public void begin(Server server) {
		if (snakeModel == null || !snakeModel.myRunning) {
			System.out.println(this.clientIndex+" player model thread starting");
			(new Thread(snakeModel)).start();
		}
	}

	/**
	 * Alert the 
	 */
	public void alertNewUser(String name) throws RemoteException {
		System.out.printf("New Player %s connected.",name);
	}

	@Override
	public void setIndex(int index) {
		this.clientIndex = index;		
	}

	@Override
	public int getIndex() throws RemoteException {
		// TODO Auto-generated method stub
		return this.clientIndex;
	}

	@Override
	public void addFood(boolean[][] isFood) {
		// TODO Auto-generated method stub
		
	}

	/**
	 * Return MultiSnake object
	 */
	public MultiSnake getSelf() throws RemoteException {
		return this;
	}

	@Override
	public void setModel(MultiSnakeModel snakeModel) throws RemoteException {
		this.snakeModel = snakeModel;
	}
}